package com.micro.center.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.micro.common.exception.GlobalException;
import com.micro.common.utils.BeanConvertUtils;
import com.micro.common.constant.Constant;
import com.micro.center.dto.SysUserDto;
import com.micro.center.entity.SysUserEntity;
import com.micro.center.mapper.SysUserMapper;
import com.micro.common.utils.DESUtils;
import com.micro.center.utils.JwtUtil;
import com.micro.common.utils.SnowFlake;
import com.micro.center.vo.CacheInfoVo;
import com.micro.common.constant.R;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author pan.shun
 * @since 2022/6/16 16:08
 */
@SuppressWarnings("unchecked")
@Slf4j
@Service
public class SysUserService extends ServiceImpl<SysUserMapper, SysUserEntity> {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SysRoleService sysRoleService;

    public R login(SysUserDto sysUserDto) {
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(
                SysUserEntity::getPassword, DESUtils.Encrypt(sysUserDto.getPassword())
        );
        queryWrapper.eq(SysUserEntity::getUserName, sysUserDto.getUserName());
        SysUserEntity userEntity = this.getOne(queryWrapper);
        if (null != userEntity) {
            if (Constant.USER_STATUS.AUDIT.equals(userEntity.getStatus())) {
                return R.error("账户审核中，请联系管理员");
            }
            if (Constant.USER_STATUS.FREEZE.equals(userEntity.getStatus())) {
                return R.error("账户已冻结，请联系管理员");
            }
            String tokenId = String.valueOf(new SnowFlake(1, 1).nextId());
            String token = JwtUtil.createToken(userEntity, tokenId);
            CacheInfoVo cacheInfoVoBuilder = new CacheInfoVo();
            cacheInfoVoBuilder.setTokenId(tokenId);
            cacheInfoVoBuilder.setToken(token);
            cacheInfoVoBuilder.setUserName(userEntity.getUserName());
            redisTemplate.opsForValue().set
                    (
                            Constant.TOKEN_CONFIG.PREFIX + tokenId,
                            cacheInfoVoBuilder,
                            Constant.TOKEN_CONFIG.EXPIRATION_TIME, TimeUnit.SECONDS
                    );

            roleSaveCache(userEntity);

            return R.success(cacheInfoVoBuilder, "登录成功");
        } else {
            return R.error("用户名或密码有误");
        }
    }

    @Async
    public void roleSaveCache(SysUserEntity userEntity) {
        sysRoleService.refreshUserRoleCache(userEntity);
    }

    public R loginOut(HttpServletRequest request) {
        String token = request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY);
        if (StringUtils.isEmpty(token)) {
            token = request.getParameter(Constant.TOKEN_CONFIG.TOKEN_KEY);
        }
        if (!StringUtils.isEmpty(token)) {
            try {
                Claims jwtClaims = JwtUtil.getJwtClaims(token);
                String tokenId = jwtClaims.getId();
                redisTemplate.delete(Constant.TOKEN_CONFIG.PREFIX + tokenId);
                return R.success("账号已退出");
            } catch (Exception e) {
                return R.error("退出登录失败");
            }
        } else {
            return R.error("退出登录失败");
        }
    }

    public R registerUser(SysUserDto sysUserDto) {
        SysUserEntity convert = BeanConvertUtils.convert(sysUserDto, SysUserEntity.class);
        try {
            if (null == convert) {
                return R.error("注册失败，请检查用户名或密码");
            }
            userCheck(convert);
            convert.setPassword(DESUtils.Encrypt(convert.getPassword()));
            convert.setStatus(Constant.USER_STATUS.AUDIT);
            this.save(convert);
            return R.success("账户注册成功");
        } catch (Exception e) {
            return R.error(e.getMessage());
        }
    }

    private void userCheck(SysUserEntity sysUserEntity) {
        if (StringUtils.isEmpty(sysUserEntity.getPassword())) {
            throw new GlobalException("密码不能为空");
        }
        if (StringUtils.isEmpty(sysUserEntity.getUserName())) {
            throw new GlobalException("用户名不能为空");
        }
        LambdaQueryWrapper<SysUserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUserEntity::getUserName, sysUserEntity.getUserName());
        int count = this.count(queryWrapper);
        if (count != 0) {
            throw new GlobalException("用户名已存在，请重试");
        }
    }

    public R getOnlineUser(HttpServletRequest request) {

        Claims jwtClaims = JwtUtil.getJwtClaims(request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY));
        String tokenId = jwtClaims.getId();

        Set<String> keys = redisTemplate.keys(Constant.TOKEN_CONFIG.PREFIX + "*");
        List<CacheInfoVo> cacheInfoVoList = null;
        if (!CollectionUtils.isEmpty(keys)) {
            cacheInfoVoList = new ArrayList<>(50);
            for (String r : keys) {
                CacheInfoVo cacheInfoVo = (CacheInfoVo) redisTemplate.opsForValue().get(r);

                if (null != cacheInfoVo) {
                    if (cacheInfoVo.getTokenId().equals(tokenId)) {
                        cacheInfoVo.setCurrentRecord(jwtClaims.getSubject());
                    }
                }
                cacheInfoVoList.add(cacheInfoVo);
            }
        }
        return R.success(cacheInfoVoList);
    }

    public R forcedOffline(String tokenId) {
        String key = Constant.TOKEN_CONFIG.PREFIX + tokenId;

        try {
            Boolean aBoolean = redisTemplate.hasKey(key);
            if (null == aBoolean) {
                aBoolean = false;
            }
            if (aBoolean) {
                redisTemplate.delete(Constant.TOKEN_CONFIG.PREFIX + tokenId);
                return R.success("用户下线成功");
            } else {
                return R.error("下线失败");
            }
        } catch (Exception e) {
            return R.error("下线失败");
        }
    }

    public R getUserList(HttpServletRequest request) {
        Claims jwtClaims = JwtUtil.getJwtClaims(request.getHeader(Constant.TOKEN_CONFIG.TOKEN_KEY));

        String userName = jwtClaims.getSubject();


        List<SysUserEntity> list = this.list();

        list.forEach(r -> {
            boolean equals = r.getUserName().equals(userName);
            if (equals) {
                r.setRecordCurrentUser(userName);
            }
        });
        return R.success(list);
    }

    public R updateUser(SysUserEntity sysUserEntity) {
        sysUserEntity.setPassword(null);
        sysUserEntity.setUserName(null);
        this.updateById(sysUserEntity);
        return R.success();
    }

    public R removeUser(String userId) {
        this.removeById(userId);
        return R.success();
    }
}
